/*
	Copyright (C) 2010 Salil Bhagurkar

	This file is part of k3

	k3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	k3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with k3.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <shared.h>

/**
 * Printk function that always prints stuff to screen
 * This uses arch_printk printing function which only prints
 * a string without formatting
 * arch_printk is provided by the architecture specific code to print
 * kernel messages.
 * All functions following printk use printk
 */
int printk(const char *fmt, ...)
{
	static char dbuf[PRINTF_BUF_LEN];
	va_list args;
	int ret_val;
	va_start(args, fmt);
	ret_val = vsnprintf(dbuf,PRINTF_BUF_LEN,fmt,args);
	arch_printk(dbuf, ret_val);
	va_end(args);
	return 0;
}

/**
 * Print a buffer by calling arch_printk
 */
int printk_buf(struct buffer *from)
{
	arch_printk(from->data, from->len);
	return 0;
}

/**
 * Debug level determines the message filter
 * Any message being printed with debug level greater than or equal to 'debug_level'
 * is printed.
 */
static u32 debug_level = D_LEVEL_OFF;

/**
 * Filter. This will filter messages based on the first few characters of the function name
 */
static char *debug_filter0 = "", *debug_filter1 = "";
static u32 debug_filter0_len = 0, debug_filter1_len = 0;
static u32 debug_delay = 0;

/**
 * Set the debug level
 */
void dprint_set_debug(u32 level, char *filter0, char *filter1, u32 delay)
{
	debug_level = level;
	debug_filter0 = filter0;
	debug_filter1 = filter1;
	debug_filter0_len = strlen(filter0);
	debug_filter1_len = strlen(filter1);
	debug_delay = delay;
}

/**
 * Print a debug message
 * This uses a buffer of PRINTF_BUF_LEN itself and then
 * calls printk. This results into double stack usage
 * Get rid of this!
 * This function is not called directly.
 * A macro 'dprint' simply defines to dprint_base.
 * This enables quick disabling of debug messages
 */
void dprint_base(u32 level, const char *function_name, const char *subject, const char *fmt, ...)
{
	bool display = false;
	//Can this be short?
	if(debug_filter0_len > 0) {
		if(debug_filter1_len > 0) {
			if(!memcmp(debug_filter0, function_name, debug_filter0_len) &&
					!memcmp(debug_filter1, function_name, debug_filter1_len))
				display = true;
		} else {
			if(!memcmp(debug_filter0, function_name, debug_filter0_len))
				display = true;
		}
	} else {
		if(!memcmp(debug_filter1, function_name, debug_filter1_len))
			display = true;
	}

	if(level >= debug_level && display) {
		arch_delay_ms(debug_delay);
		static char dbuf[PRINTF_BUF_LEN];
		va_list args;
		int ret_val;
		va_start(args, fmt);
		vsnprintf(dbuf,PRINTF_BUF_LEN,fmt,args);
		printk("d%u> %s: %s (%s)\n", level, function_name, dbuf, subject);
		va_end(args);
	}
}

/**
 * Print character for hex printing
 * Doesn't show special characters (Those that may not be displayed)
 */
static void memchar(u8 c)
{
	if(c >= '!' && c <= '~') {
		printk("%c", c);
	} else {
		printk(".");
	}
}

/**
 * Print memory like a hex editor :P
 */
int printmem(void *start, u32 len)
{
	char *c;
	u32 i, j, max;
	c = start;
	for(i = 0; i < len; i+=64) {
		printk("0x%x : ", c+i);
		max = 64 < (len - i) ? 64 : len - i;
		for(j = 0; j < max; j++) {
			memchar((u8)*(c+i+j));
		}
		printk("\n");
	}
	return 0;
}

/**
 * Print 32 bit words
 */
int printwords(void *start, u32 count)
{
	u32 *c;
	u32 i, j, max;
	c = (u32 *)start;
	for(i = 0; i < count; i += 6) {
		printk("%8x: ", c + i);
		max = 6 < (count - i) ? 6 : count - i;
		for(j = 0; j < max; j++) {
			printk(" %8x", *(c + i + j));
		}
		printk("\n");
	}
	return 0;
}

/**
 * Error messages according to error.h file
 */
char *errors[] = {"Invalid parameter",
"Parameter out of bound",
"Function not supported",
"Unknown error",
"Invalid state",
"Timeout",
"Low level error",
"Not detected",
"Memory error",
"Not found",
"No such device",
"No data available"};

/**
 * Print the error message
 */
int printerror(int err)
{
	if(is_error(err))
		return printk("Error = %s", errors[-(err+1)]);
	else if(err == 0)
		return printk("Success");
}
